import AESUtil from './AESUtil';
import EventPublisher from './EventPublisher';
import LocalStorageImpl from './Impl/LocalStorageImpl';
import MapStorageImpl from './Impl/MapStorageImpl';
import ObjectStorageImpl from './Impl/ObjectStorageImpl';
import SessionStorageImpl from './Impl/SessionStorageImpl';

import type { IStorage } from './types';

/**
 * 智能存储类，支持多种存储类型、可选加密、全局过期时间与 key 前缀
 *
 * @example
 *   // 使用示例
 *   const storage = new SmartStorage({
 *     encryptEnabled: true,
 *     globalExpirationTime: 3600, // 1小时过期
 *     prefixKey: 'app_',
 *     storageType: 'local'
 *   });
 *
 *   // 设置数据
 *   storage.set('user', { name: 'John' }, 1800);
 *
 *   // 获取数据
 *   const user = storage.get('user');
 *
 *   // 监听storageChange事件
 *   window.addEventListener('storageChange', event => {
 *     console.log('Storage changed:', event.detail);
 *     // 处理存储变化逻辑
 *   });
 */
class SmartStorage {
	private readonly storage: IStorage;
	private readonly prefixKey: string;
	private readonly globalExpirationTime: number;
	private readonly encryptEnabled: boolean;
	private readonly storageType: 'local' | 'map' | 'object' | 'session';

	/**
	 * 构造函数，初始化存储类型、加密、过期时间、key 前缀等
	 *
	 * @param options 配置项
	 *
	 *   - customStorage: 自定义存储实现
	 *   - encryptEnabled: 是否启用加密
	 *   - globalExpirationTime: 全局过期时间（秒）
	 *   - prefixKey: key 前缀
	 *   - storageType: 存储类型
	 *   - secretKey: 加密密钥
	 */
	constructor(
		options: {
			customStorage?: IStorage;
			encryptEnabled?: boolean;
			globalExpirationTime?: number;
			prefixKey?: string;
			secretKey?: string;
			storageType?: 'local' | 'map' | 'object' | 'session';
		} = {}
	) {
		this.storageType = options.storageType ?? 'local';
		this.prefixKey = options.prefixKey ?? '';
		this.globalExpirationTime = options.globalExpirationTime ?? 0;
		this.encryptEnabled = options.encryptEnabled ?? false;
		if (options.secretKey) {
			AESUtil.setSecretKey(options.secretKey);
		}

		let storageInstance: IStorage;

		if (options.customStorage) {
			storageInstance = options.customStorage;
		} else {
			switch (this.storageType) {
				case 'local':
					storageInstance = new LocalStorageImpl();
					break;
				case 'session':
					storageInstance = new SessionStorageImpl();
					break;
				case 'map':
					storageInstance = new MapStorageImpl();
					break;
				case 'object':
				default:
					storageInstance = new ObjectStorageImpl();
					break;
			}
		}

		this.storage = storageInstance;
	}

	/**
	 * 设置存储项，支持可选过期时间和强制覆盖，支持加密
	 *
	 * @param key 键名
	 * @param value 任意类型的值
	 * @param expirationTime 过期时间（秒），优先级高于全局过期时间
	 * @param force 是否强制覆盖已存在 key
	 */
	set(key: string, value: unknown, expirationTime?: number, force: boolean = false): void {
		const fullKey = this.prefixKey + key;
		let success = false;
		if (!force && this.storage.keyExists(fullKey)) {
			console.warn(`Key "${key}" already exists. Use force=true to overwrite.`);
		} else {
			const itemExpirationTime = expirationTime ?? this.globalExpirationTime;
			const data = JSON.stringify({
				expires: itemExpirationTime ? Date.now() + itemExpirationTime * 1000 : null,
				value
			});
			let encryptedData = data;
			// 若启用加密，则加密存储内容
			if (this.encryptEnabled) {
				encryptedData = AESUtil.encrypt(data);
			}
			this.storage.setItem(fullKey, encryptedData);
			success = true;
		}
		EventPublisher.dispatchEvent(
			new CustomEvent('storageChange', {
				detail: { action: 'set', key, success }
			})
		);
	}

	/**
	 * 获取指定 key 的值，自动解密与过期校验，支持传入默认值
	 *
	 * @param key 键名
	 * @param defaultValue 默认返回值（可选），当未获取到值时返回
	 * @returns 存储的值，若不存在或已过期返回 null 或 defaultValue
	 */
	get<T>(key: string, defaultValue?: T): T {
		const fullKey = this.prefixKey + key;
		const encryptedData = this.storage.getItem(fullKey);
		let success = encryptedData !== null;
		let value: T | null = null;
		if (success && encryptedData) {
			try {
				// 若启用加密，先解密
				const data = this.encryptEnabled ? AESUtil.decrypt(encryptedData) : encryptedData;
				const parsedData = JSON.parse(data) as { expires: number | null; value: T };
				if (parsedData.expires && parsedData.expires < Date.now()) {
					this.storage.removeItem(fullKey);
					success = false;
				} else {
					value = parsedData.value;
				}
			} catch (error) {
				console.error('Decryption failed or the data format is incorrect', error);
				success = false;
			}
		}
		EventPublisher.dispatchEvent(
			new CustomEvent('storageChange', {
				detail: { action: 'get', key, success, value }
			})
		);
		if (value === null && typeof defaultValue !== 'undefined') {
			return defaultValue as T;
		}
		return value as T;
	}

	/**
	 * 移除指定 key 的存储项
	 *
	 * @param key 键名
	 */
	remove(key: string): void {
		const fullKey = this.prefixKey + key;
		const exists = this.storage.keyExists(fullKey);
		this.storage.removeItem(fullKey);
		const success = exists;
		EventPublisher.dispatchEvent(
			new CustomEvent('storageChange', {
				detail: { action: 'remove', key, success }
			})
		);
	}

	/** 清空所有存储内容 */
	clear(): void {
		this.storage.clear();
		EventPublisher.dispatchEvent(
			new CustomEvent('storageChange', {
				detail: { action: 'clear', success: true }
			})
		);
	}
}

export { AESUtil, EventPublisher, SmartStorage };
